package com.ruoyi.framework.websocket;

import java.util.concurrent.Semaphore;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * websocket 消息处理
 * 
 * @author ruoyi
 */
@Component
@ServerEndpoint("/websocket/{joinId}")
public class WebSocketServer
{
    /**
     * WebSocketServer 日志控制器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);

    /**
     * 默认最多允许同时在线人数100
     */
    public static int socketMaxOnlineCount = 100;

    private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount);

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("joinId") String joinId) throws Exception
    {
        boolean semaphoreFlag = false;
        // 尝试获取信号量
        semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore);
        if (!semaphoreFlag)
        {
            // 未获取到信号量
            LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount);
            WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数：" + socketMaxOnlineCount);
            session.close();
        }
        else
        {
            // 添加用户
            //WebSocketUsers.put(session.getId(), session);
            WebSocketUsers.put(joinId, session);
            LOGGER.info("\n 建立连接 - {}", session);
            LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size());
            //printSession(session, "Open" + joinId);
            WebSocketUsers.sendMessageToUserByText(session, "连接成功");
        }
    }

    /**
     * 连接关闭时处理
     */
    @OnClose
    public void onClose(Session session)
    {
        LOGGER.info("\n 关闭连接 - {}", session);
        // 移除用户
        boolean removeFlag = WebSocketUsers.remove(session.getRequestParameterMap().get("joinId").toString());
        if (!removeFlag)
        {
            // 获取到信号量则需释放
            SemaphoreUtils.release(socketSemaphore);
        }
    }

    /**
     * 抛出异常时处理
     */
    @OnError
    public void onError(Session session, Throwable exception) throws Exception
    {
        if (session.isOpen())
        {
            // 关闭连接
            session.close();
        }
        String joinId = session.getRequestParameterMap().get("joinId").toString();
        LOGGER.info("\n 连接异常 - {}", joinId);
        LOGGER.info("\n 异常信息 - {}", exception);
        // 移出用户
        WebSocketUsers.remove(joinId);
        // 获取到信号量则需释放
        SemaphoreUtils.release(socketSemaphore);
    }

    /**
     * 服务器接收到客户端消息时调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session)
    {
        //printSession(session, message);
        // 解析客户端发送过来的报文
        JSONObject jsonObject = JSON.parseObject(message);
        //LOGGER.info(" jsonObject - {}", jsonObject);
        // 消息类型
        String type = jsonObject.getString("type");
        // 获取接收人
        String toJoinId = jsonObject.getString("toJoinId");
        //LOGGER.info(" toJoinId - {}", toJoinId);
        // 获取消息
        String msg = jsonObject.getString("contentText");
        //LOGGER.info(" msg - {}", msg);
        if(StringUtils.isNotEmpty(type) && type.equals("MSG") && StringUtils.isNotEmpty(toJoinId) && WebSocketUsers.getUsers().containsKey(toJoinId)) {
            WebSocketUsers.sendMessageToJoinByText(type, toJoinId, msg);
        } else if(type.equals("SYN")) {
            //LOGGER.info("ACK - {}", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"));
            WebSocketUsers.sendMessageToJoinByText("ACK", toJoinId, msg + ", " + DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"));
        } else {
            msg = message.replace("你", "我").replace("吗", "");
            WebSocketUsers.sendMessageToUserByText(session, msg);
        }
    }

    /**
     * session information
     */
    private void printSession(Session session, String info)
    {
        LOGGER.info(" 提示信息 - {}", info);
        LOGGER.info(" session getId - {}", session.getId());
        LOGGER.info(" session getBasicRemote - {}", session.getBasicRemote());
        LOGGER.info(" session getOpenSessions - {}", session.getOpenSessions());
        LOGGER.info(" session getContainer - {}", session.getContainer());
        LOGGER.info(" session getAsyncRemote - {}", session.getAsyncRemote());
        LOGGER.info(" session getMaxIdleTimeout - {}", session.getMaxIdleTimeout());
        LOGGER.info(" session getMaxBinaryMessageBufferSize - {}", session.getMaxBinaryMessageBufferSize());
        LOGGER.info(" session getMaxTextMessageBufferSize - {}", session.getMaxTextMessageBufferSize());
        LOGGER.info(" session getMessageHandlers - {}", session.getMessageHandlers());
        LOGGER.info(" session getNegotiatedExtensions - {}", session.getNegotiatedExtensions());
        LOGGER.info(" session getNegotiatedSubprotocol - {}", session.getNegotiatedSubprotocol());
        LOGGER.info(" session getMaxIdleTimeout - {}", session.getMaxIdleTimeout());
        LOGGER.info(" session getAsyncRemote - {}", session.getAsyncRemote());
        LOGGER.info(" session getPathParameters - {}", session.getPathParameters());
        LOGGER.info(" session getProtocolVersion - {}", session.getProtocolVersion());
        LOGGER.info(" session getQueryString - {}", session.getQueryString());
        LOGGER.info(" session getRequestParameterMap - {}", session.getRequestParameterMap());
        LOGGER.info(" session getRequestURI - {}", session.getRequestURI());
        LOGGER.info(" session getUserPrincipal - {}", session.getUserPrincipal());
        LOGGER.info(" session getUserProperties - {}", session.getUserProperties());
    }
}
